﻿using System;
using System.Reflection;

namespace Accona.Remoting.Remoting
{
    public class RemoteObjectExecution
    {
        private readonly Guid applicationId;
        private readonly IResolver resolver;

        public RemoteObjectExecution(Guid applicationId, IResolver resolver)
        {
            this.applicationId = applicationId;
            this.resolver = resolver;
        }

        public ExecutionResult Execute(byte[] bytes)
        {
            MethodInvocationInfo methodInvocationInfo = new MethodSerializer(applicationId).DeserializeMethodCall(bytes);
            if (!methodInvocationInfo.SourceMetaData.ApplicationId.Equals(applicationId) &&
                methodInvocationInfo.SourceMetaData.TargetId.Equals(applicationId))
            {
                MethodInfo methodInfo = methodInvocationInfo.Type.GetMethod(methodInvocationInfo.MethodName,
                                                                            methodInvocationInfo.ParameterTypes);
                object o = resolver.Resolve(methodInfo.DeclaringType);
                if (o != null)
                {
                    object result = methodInfo.Invoke(o, methodInvocationInfo.Parameters);
                    return new ExecutionResult
                               {
                                   ResultValue = result,
                                   MethodInvocationInfo = methodInvocationInfo,
                                   MethodInfo = methodInfo
                               };
                }
            }
            return null;
        }

        #region Nested type: ExecutionResult

        public class ExecutionResult
        {
            public object ResultValue { get; set; }

            public MethodInvocationInfo MethodInvocationInfo { get; set; }

            public MethodInfo MethodInfo { get; set; }
        }

        #endregion
    }
}